const orm = require('orm')
const path = require('path')
const dao = require(path.join(process.cwd(),"dao/Dao"));
const GoodAttributeDAO = require(path.join(process.cwd(), 'dao/GoodAttributeDAO'))
const _ = require('lodash');
const fs = require('fs');
const { upload_config } = require('../config/upload');



// 获取商品列表
module.exports.getGoodsList = function(params, cb) {
    if (!params.pageNum) return cb('pageNum 错误')
	if (!params.pageSize) return cb('pageSize 错误')
    let condistions = {}

    condistions['columns'] = {}
    if (params.query) {
        condistions['columns']['goods_name'] = orm.like('%' + params.query + '%')
    }
    condistions['columns']['is_del'] = '0'
    dao.countByConditions('GoodModel', condistions, (err, count) => {
        if (err) return cb(err)
         pageNum = parseInt(params.pageNum)
         pageSize = parseInt(params.pageSize)
         offset = (pageNum - 1) * pageSize
         if (offset >= count) {
			offset = count
		 }
		limit = pageSize

        // 构建条件
        condistions['offset'] = offset
        condistions['limit'] = limit
        // only表示不是查询全部字段，只查询指定字段
        condistions['only'] = ['goods_id', 'goods_name', 'goods_price', 'goods_weight', 'goods_state', 'add_time', 'goods_number', 'upd_time', 'hot_mumber', 'is_promote']
        // 默认add_time desc 降序排列
        condistions['order'] = '-add_time'
        dao.list('GoodModel', condistions, (err, goods) => {
            if (err) return cb(err)
            var resultData = {}
            resultData['total'] = count
            resultData['goods'] = _.map(goods, good => {
                // 返回一个没有列入排除key属性的对象
                return _.omit(good, "goods_introduce","is_del","goods_big_logo","goods_small_logo","delete_time")
            })
            cb(err, resultData)
        })
    })
}

// 创建商品
module.exports.createGood = function (params, cb) {
    // 验证参数 & 生成数据
    generateGoodInfo(params)
    //检查商品名称名称是否重复
    .then(checkGoodName)
    // 创建商品基本信息
    .then(createGoodInfo)
    // 更新商品图片
    .then(doUpdateGoodPics)
    // 更新商品参数
    .then(doUpdateGoodAttributes)
    // 挂载图片
    .then(doGetAllPics)
    // 挂载属性
    .then(doGetAllAttrs)
    .then((info) => {
        cb(null, info.good)
    })
    .catch((err) => {
        cb(err)
    })
}

// 更新商品
module.exports.updateGood = function (id, params, cb) {
    params.goods_id = id
    generateGoodInfo(params)
    .then(checkGoodName)
    .then(updateGoodInfo)
    .then(doUpdateGoodPics)
    .then(doUpdateGoodAttributes)
    .then(doGetAllPics)
    .then(doGetAllAttrs)
    .then((info) => {
        console.log('info', info)
        cb(null, info.good)
    })
    .catch((err) => {
        cb(err)
    })
}


// 删除商品
module.exports.delGood = function (id, cb) {
    if (!id) cb('商品ID不能为空')
    if (isNaN(parseInt(id))) cb('商品ID必须为数字')
    dao.update('GoodModel', id, {
        is_del: '1',
        delete_time: Date.parse(new Date()) / 1000,
        upd_time: Date.parse(new Date()) / 1000
    }, (err) => {
        if (err) cb(err)
        cb(null)
    })
}

// 获取商品详情
module.exports.getGoodById = function(id, cb) {
   getGoodInfo({goods_id: id})
   .then(doGetAllPics)
   .then(doGetAllAttrs)
   .then((info) => {
        cb(null, info.good)
   })
   .catch((err) => {
        cb(err)
   })
}

// 更新商品图片
module.exports.updateGoodPics = function (id, pics, cb) {
    if (!id) return cb('商品ID不能为空')
    if(isNaN(id)) return cb('商品IDb必须为数字')
    getGoodInfo({goods_id: id, pics})
    .then(doUpdateGoodPics)
    .then(doGetAllPics)
    .then(doGetAllAttrs)
    .then((info) => {
        cb(null, info.good)
    })
    .catch((err) => {
        cb(err)
    })
}

// 更新商品属性
module.exports.updateGoodAttributes = function (id, attrs, cb) {
    getGoodInfo({ goods_id: id, attrs})
    .then(doUpdateGoodAttributes)
    .then(doGetAllPics)
    .then(doGetAllAttrs)
    .then((info) => {
        cb(info.good)
    })
    .catch((err) => {
        cb(err)
    })
}

// 更新商品状态
module.exports.updateGoodState = function(id, state, cb) {
    getGoodInfo({ goods_id: id, goods_state: state})
    .then(updateGoodInfo)
    .then(doGetAllPics)
    .then(doGetAllAttrs)
    .then((info) => {
        cb(null, info.good)
    })
    .catch((err) => {
        cb(err)
    })
}




/***************商品功能函数区*************** */
function generateGoodInfo (params) {
    return new Promise((resolve, reject) => {
        console.log('generateGoodInfo')
        let info = {}
        if (params.goods_id) info['goods_id'] = params.goods_id // 编辑需id

        //以下为必填
        if (!params.goods_name) return reject('商品名称不能为空')
        info['goods_name'] = params.goods_name

        if (!params.goods_price) return reject('商品价格不能为空')
        let price = parseFloat(params.goods_price)
        if (isNaN(price) || price < 0) return reject('商品价格不正确')
        info['goods_price'] = price

        if (!params.goods_number) return reject('商品数量不能为空')
        let num = parseInt(params.goods_number)
        if (isNaN(num) || num < 0) return reject('商品数量不正确')
        info['goods_number'] = num

        if (!params.goods_cat) return reject('商品没有设置所属分类')
        let cats = params.goods_cat.split(',')
        if (cats.length > 0) {
            info['cat_one_id'] = cats[0]
        }
        if (cats.length > 1) {
            info['cat_two_id'] = cats[1]
        }
        if (cats.length > 2) {
            info['cat_three_id'] = cats[2]
            info['cat_id'] = cats[2]
        }
  
        // 以下为非必填
        if (params.goods_weight) {
            let weight = params.goods_weight
            if (isNaN(weight) || weight < 0) return reject('商品重量格式不正确')
            info['goods_weight'] = weight
        } else {
            info['goods_weight'] = 0
        }

        if (params.goods_introduce) {
            info['goods_introduce'] = params.goods_introduce
        }
        if (params.goods_big_logo) {
            info['goods_big_logo'] = params.goods_big_logo
        } else {
            info['goods_big_logo'] = ''
        }

        if (params.goods_small_logo) {
            info['goods_small'] = params.goods_small
        } else {
            info['goods_small'] = ''
        }

        if (params.goods_state) {
            info['goods_state'] = params.goods_state
        }
        // 图片
        if (params.pics) {
            info['pics'] = params.pics
        }
        // 属性
        if (params.attrs) {
            info['attrs'] = params.attrs
        }

        // 时间戳
        info['add_time'] = Date.parse(new Date()) / 1000
        info['upd_time'] = Date.parse(new Date()) / 1000
        info['is_del'] = '0'

        if (params.hot_mumber) {
            let hot_num = parseInt(params.hot_mumber) 
            if (isNaN(hot_num) || hot_num < 0) return reject('热销品数量不正确')
            info['hot_mumber'] = hot_num
        } else {
            info['hot_mumber'] = 0
        }

        info['is_promote'] = info['is_promote'] ? info['is_promote'] : false
        resolve(info)
    })
}

function checkGoodName (info) {
    return new Promise((resolve, reject) => {
        console.log('checkGoodName')
        dao.findOne('GoodModel', {
            goods_name: info.goods_name,
            is_del: '0'
        }, (err, good) => {
            if (err) return reject(err)
            if (!good) return resolve(info)
            if (good.goods_id == info.goods_id) return resolve(info)
            return reject('商品名称已经存在')
        })
    })
}

function createGoodInfo (info) {
    return new Promise((resolve, reject) => {
        console.log('createGoodInfo')
        // _.clone(obj) 浅拷贝对象
        dao.create('GoodModel', _.clone(info), (err, newGood) => {
            if (err) return reject('创建商品基本信息失败')
            newGood.goods_cat = newGood.getGoodsCat()
            info.good = newGood
            return resolve(info)
        })
    })
}

function doUpdateGoodPics (info) {
    return new Promise((resolve, reject) => {
        console.log('doUpdateGoodPics')
        let good = info.good
        if (!good.goods_id) return reject('更新商品图片失败')

        if (!info.pics) return resolve(info)

        dao.list('GoodPicModel', {
            columns: {
                goods_id: good.goods_id
            }
        }, (err, oldpics) => {
            if (err) return reject('获取商品图片列表失败')

            let batchFns = []
            let newpics = info.pics ? info.pics :  []
            let newpicsKV = _.keyBy(newpics, 'pics_id')
            let oldpicsKV = _.keyBy(oldpics, 'pics_id')
            
            /**保存图片集合 */
            let addNewPics = []
            let reservedOldPics = []
            let delOldPics = []

            // 如果提交的新的数据中有老的数据的pics_id就说明保留数据，否则就删除
            _(oldpics).forEach(function(pic) {
                if (newpicsKV[pic.pics_id]) {
                    reservedOldPics.push(pic)
                } else {
                    delOldPics.push(pic)
                }
            })
            // 如果提交的数据不存在pics_id字段说明是新创建的数据
            _(newpics).forEach(function(pic) {
                if (!pic.pics_id && pic.pic) {
                    addNewPics.push(pic)
                }
            })

            /**开始处理商品图片数据逻辑 */
            // 1. 删除商品图片数据集合
            _(delOldPics).forEach(function(pic) {
                // 1.1 删除图片物理路径
                batchFns.push(removeGoodPicFile(path.join(process.cwd(),pic.pics_big)))
                batchFns.push(removeGoodPicFile(path.join(process.cwd(),pic.pics_mid)))
                batchFns.push(removeGoodPicFile(path.join(process.cwd(),pic.pics_sma)))
                // 1.2 数据库中删除图片数据记录
                batchFns.push(removeGoodPic(pic))
            }) 

            // 2. 处理新建图片的集合
            _(addNewPics).forEach(function(pic) {
                if (!pic.pics_id && pic.pic) {
                    // 2.1 通过原始图片路径裁剪出需要的图片
                    let src = path.join(process.cwd(), pic.pic)
                    // path.sep 将特定文字分隔符 ‘\\' 或 ‘/' 的字符串转换成数组对象
                    let tmp = src.split(path.sep)
                    let filename = tmp[tmp.length - 1]
                    pic.pics_big = "/uploads/goodspics/big_" + filename
                    pic.pics_mid = "/uploads/goodspics/mid_" + filename
                    pic.pics_sma = "/uploads/goodspics/sma_" + filename
                    batchFns.push(clipImage(src, path.join(process.cwd(), pic.pics_big), 800, 800))
                    batchFns.push(clipImage(src, path.join(process.cwd(), pic.pics_mid), 400, 400))
                    batchFns.push(clipImage(src, path.join(process.cwd(), pic.pics_sma), 200, 200))
                    pic.goods_id = good.goods_id
                    // 2.2 数据库中新建数据记录
					batchFns.push(createGoodPic(pic));
                }
            })

            // 如果没有任何图片操作就返回
            if (batchFns.length == 0) {
                return resolve(info)
            }

            // 批量执行所有操作
            Promise.all(batchFns)
            .then(() => {
                resolve(info)
            })
            .catch((err) => {
                if (err) return reject(err)
            })
        })
    })
}

function removeGoodPicFile(path) {
    return new Promise((resolve, reject) => {
        console.log('removeGoodPicFile')
        // 从文件系统中删除文件或符号链接
        fs.unlink(path, function(err, res) {
            resolve()
        })
    })
}

function removeGoodPic (pic) {
    //删除商品图片对象
    return new Promise((resolve, reject) => {
        console.log('removeGoodPic')
        if (!pic || !pic.remove) return reject('删除商品图片记录失败')
        pic.remove(function(err) {
            if (err) return reject('删除失败')
            resolve()
        })
    })
}

function clipImage (srcPath, savePath, newWidth, newHeight) {
    return new Promise((resolve, reject) => {
        let readStream = fs.createReadStream(srcPath)
        let writeStream = fs.createWriteStream(savePath)
        readStream.pipe(writeStream)
        readStream.on('end', function () {
            resolve()
        })
    })
}

function createGoodPic (pic) {
    return new Promise((resolve, reject) => {
        console.log('createGoodPic')
        if (!pic) return reject('图片对象不能为空')
        let GoodPicModel = dao.getModel('GoodPicModel')
        // GoodPicModel.create('GoodPicModel', pic, function(err, newPic) {}) ?
        GoodPicModel.create(pic, function(err, newPic) {
            if (err) return reject('创建图片数据失败')
            resolve()
        })
    })
}

function doUpdateGoodAttributes (info) {
    return new Promise((resolve, reject) => {
        console.log('doUpdateGoodAttributes')
        let good = info.good
        if (!good.goods_id) return reject('获取商品图片必须先获取商品信息')
        if (!good.attrs) return resolve(info)
        GoodAttributeDAO.clearGoodAttributes(good.goods_id, function(err) {
            if (err) return reject('清理原始商品参数失败')
            const newAttrs = info.attrs ? info.attrs: []
            if (newAttrs) {
                const createFns = []

                _(newAttrs).forEach(function(newAttr) {
                    newAttr.goods_id = good.goods_id
                    if (newAttr.attr_value) {
                        if (newAttr.attr_value instanceof Array) {
                            newAttr.attr_value = newAttr.attr_value.join(',')
                        } else {
                            newAttr.attr_value = newAttr.attr_value
                        }
                    } else  {
                        newAttr.attr_value = "";
                          // _.clone(obj) 浅拷贝对象
                        createFns.push(createGoodAttribute(_.clone(newAttr)));
                    }
                })

                if (createFns.length == 0) return resolve(info)

                Promise.all(createFns)
                .then(() => {
                    resolve(info)
                })
                .catch((err) => {
                    if (err) return reject(err)
                })
            }
        })
    })
}

function createGoodAttribute (GoodAttribute) {
    return new Promise((resolve, reject) => {
        console.log('createGoodAttribute')
        // _.omit(obj, 'key1', 'key2')返回一个没有列入排除key属性的对象
        dao.create('GoodAttributeModel', _.omit(GoodAttribute, 'delete_time'), function(err, newAttr) {
            if(err) return reject("创建商品参数失败");
			resolve(newAttr);
        })
    })
}

function doGetAllPics (info) {
    return new Promise((resolve,reject) => {
        console.log('doGetAllPics')
        let good = info.good
        if(!good.goods_id) return reject("获取商品图片必须先获取商品信息")
        // 将最新的数据挂载到"info"中的"good"对象上
        dao.list('GoodPicModel', {
            columns: {
                goods_id: good.goods_id
            }
        }, function(err,goodPics) {
            if (err) return reject('获取所有商品列表图片列表失败')
            _(goodPics).forEach(function(pic) {
                if (pic.pics_big.indexOf('http') == 0) {
                    pic.pics_big_url = pic.pics_big
                } else {
                    pic.pics_big_url = upload_config.baseURL + pic.pics_big
                }
                if (pic.pics_mid.indexOf('http') == 0) {
                    pic.pics_mid_url = pic.pics_mid
                } else {
                    pic.pics_mid_url = upload_config.baseURL + pic.pics_mid
                }
                if (pic.pics_sma.indexOf('http') == 0) {
                    pic.pics_sma_url = pic.pics_sma
                } else {
                    pic.pics_sma_url = upload_config.baseURL + pic.pics_sma
                }
            })
            info.good.pics = goodPics
            resolve(info)
        })
    })
}

function doGetAllAttrs (info)  {
    return  new Promise ((resolve, reject) => {
        console.log('doGetAllAttrs')
        let good = info.good
        if (!good.goods_id) return reject('获取商品图片必须先获取商品信息')
        GoodAttributeDAO.list(good.goods_id, function(err, goodAttrs) {
            if (err) reject('获取所有商品参数列表失败')
            info.good.attrs = goodAttrs
            resolve(info)
        })
    })
}

function updateGoodInfo (info) {
    return new Promise((resolve, reject) => {
        console.log('updateGoodInfo')
        if (!info.goods_id) return reject('商品ID不存在')
        dao.update('GoodModel', info.goods_id, _.clone(info), (err, good) => {
            if (err) reject('更新商品基本信息失败')
            info.good = good
             return resolve(info)
        })
    })
}

function getGoodInfo (info) {
    return new Promise((resolve, reject) => {
        console.log('getGoodInfo')
        if (!info || !info.goods_id || isNaN(info.goods_id)) return reject('商品ID格式不正确')
        dao.show('GoodModel', info.goods_id, (err,good) => {
            if (err) reject('获取商品基本信息失败')
            good.goods_cat = good.getGoodsCat()
            info.good = good
            return resolve(info)
        })
    })
}